package com.ashin.rsa;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import javax.crypto.Cipher;

import org.junit.Test;

import com.ashin.util.BinAndHex;

/**
 * https://blog.csdn.net/qq_18870023/article/details/52596808
 * 
 * @author Ashin
 *
 */
public class Main {

    private String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfWVDPRdkC/XrbVfCCNBAZJSpHqHdhZkldqpsB4MwqrDANOSrguAGtETHmENbSCIE7aRH/M2oh4KNXrR35qxPnMxFFgzeU/aoxTRRNeHv61h5EYcDs7vjA7a//5uU5j/Xr72cDVVicPjxm0I3ISgJ/FoX+vfC/GFO+iVsd4LQuJQIDAQAB";

    private String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ9ZUM9F2QL9ettV8II0EBklKkeod2FmSV2qmwHgzCqsMA05KuC4Aa0RMeYQ1tIIgTtpEf8zaiHgo1etHfmrE+czEUWDN5T9qjFNFE14e/rWHkRhwOzu+MDtr//m5TmP9evvZwNVWJw+PGbQjchKAn8Whf698L8YU76JWx3gtC4lAgMBAAECgYAtG6N8iVE9P3Qf0twaf5JvC85EKrRgpgvur/ThOzmQet2/YId6xZvz2gI+FlY5bp7mqn+ltnA81tJmZ2Ms4fjn7s2ZTqkFdxOJC4Db9eYLuIZzX9DjfIxWx3YqFfRUr1huKDqpmDD2DmSJ2FRJHLjrJl9GT0ME1YUbJnTKcGYHoQJBAOE1auRHDtZx0zTzUS+EMfdDx5YSMUvvWDHWTqaQhAY1xwpABQqxbFWxNzovDhFOmrCVSUho7V8zr0kTt55DPt8CQQC1IrlxwcVoHftqrRSy6rxqeEt5YaIr7P4K0rdgXdXVE/dng7KiKLOdjStviaZyhTKtHCOKYFpFaD84/mrvTyd7AkEAmcGmoQQClVZRJK2amB5hHrgf48236mgWhrASMpYoDTVaFx1uU8aeeELtucO2jwpjgnvp9I3uwji/S90yV9MBcQJAApb5gcfcc62iD5dj6V7zzK3lnlmoAOrFgxAaMRWGXiKH8gHvBuSAFOuUyGZ2a8K9w73YQD06bS2dYco5ayx9iwJAd/PRPI8fbVxLyYHselJl5z1WzkMaPuDTcLDzUpuMTEx4t9ZlpaV/5iTeEI53GuJ67cLLPKlQuJAHkhnNnzoiLg==";

    private String explicitText = "hello rsa";

    private String signedData = "hi 我是要被签名的文字";

    @Test
    public void generateKeyPair() throws Exception {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(2048, SecureRandom.getInstance("SHA1PRNG", "SUN"));
        KeyPair kp = kpg.generateKeyPair();

        PublicKey publicKey = kp.getPublic();
        PrivateKey privateKey = kp.getPrivate();

        // 获取公钥，并以base64格式打印出来
        // 公钥：MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfWVDPRdkC/XrbVfCCNBAZJSpHqHdhZkldqpsB4MwqrDANOSrguAGtETHmENbSCIE7aRH/M2oh4KNXrR35qxPnMxFFgzeU/aoxTRRNeHv61h5EYcDs7vjA7a//5uU5j/Xr72cDVVicPjxm0I3ISgJ/FoX+vfC/GFO+iVsd4LQuJQIDAQAB
        System.out.println("公钥：" + new String(Base64.getEncoder().encode(publicKey.getEncoded())));

        // 获取私钥，并以base64格式打印出来
        // 私钥：MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ9ZUM9F2QL9ettV8II0EBklKkeod2FmSV2qmwHgzCqsMA05KuC4Aa0RMeYQ1tIIgTtpEf8zaiHgo1etHfmrE+czEUWDN5T9qjFNFE14e/rWHkRhwOzu+MDtr//m5TmP9evvZwNVWJw+PGbQjchKAn8Whf698L8YU76JWx3gtC4lAgMBAAECgYAtG6N8iVE9P3Qf0twaf5JvC85EKrRgpgvur/ThOzmQet2/YId6xZvz2gI+FlY5bp7mqn+ltnA81tJmZ2Ms4fjn7s2ZTqkFdxOJC4Db9eYLuIZzX9DjfIxWx3YqFfRUr1huKDqpmDD2DmSJ2FRJHLjrJl9GT0ME1YUbJnTKcGYHoQJBAOE1auRHDtZx0zTzUS+EMfdDx5YSMUvvWDHWTqaQhAY1xwpABQqxbFWxNzovDhFOmrCVSUho7V8zr0kTt55DPt8CQQC1IrlxwcVoHftqrRSy6rxqeEt5YaIr7P4K0rdgXdXVE/dng7KiKLOdjStviaZyhTKtHCOKYFpFaD84/mrvTyd7AkEAmcGmoQQClVZRJK2amB5hHrgf48236mgWhrASMpYoDTVaFx1uU8aeeELtucO2jwpjgnvp9I3uwji/S90yV9MBcQJAApb5gcfcc62iD5dj6V7zzK3lnlmoAOrFgxAaMRWGXiKH8gHvBuSAFOuUyGZ2a8K9w73YQD06bS2dYco5ayx9iwJAd/PRPI8fbVxLyYHselJl5z1WzkMaPuDTcLDzUpuMTEx4t9ZlpaV/5iTeEI53GuJ67cLLPKlQuJAHkhnNnzoiLg==
        System.out.println("私钥：" + new String(Base64.getEncoder().encode(privateKey.getEncoded())));
    }

    @Test
    public void encrypt() throws Exception {
        // 获取公钥
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] publicKeyByte = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyByte);
        PublicKey generatePublic = keyFactory.generatePublic(keySpec);

        // 加密
        // java默认"RSA"="RSA/ECB/PKCS1Padding"
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, generatePublic);
        byte[] doFinal = cipher.doFinal(explicitText.getBytes());

        System.out.println(BinAndHex.byte2HexStr(doFinal));
    }

    @Test
    public void decrypt() throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        PrivateKey generatePrivate = keyFactory.generatePrivate(keySpec);

        // 解密
        String text = "85D8882101D09201C44C7C5147CD26BCD861E0F50D0E8510741EB4554D80CE1FA0450E69E70660A04E8047EEF9EB6E9341209DD400C9D5F8307C3C0AE491BD863BAAC478FCA885D99A02A62A7EEE7807A3E1E621D70ADE58F3B6906A6912FFF33CCC69C8B66AB6A98F8CB4D782AC1222F8E8B98D7747C2071AD5598DD2E8ED11";
        byte[] hexStr2Byte = BinAndHex.hexStr2Byte(text);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, generatePrivate);

        byte[] doFinal = cipher.doFinal(hexStr2Byte);
        byte[] doFinal1 = cipher.doFinal(hexStr2Byte);
        System.out.println(new String(doFinal, "UTF-8"));
        System.out.println(new String(doFinal1, "UTF-8"));
    }

    @Test
    public void signWithPrivateKey() throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        PrivateKey generatePrivate = keyFactory.generatePrivate(keySpec);

        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initSign(generatePrivate);
        signature.update(signedData.getBytes());

        byte[] sign = signature.sign();

        // d+YIUvpJQaqKovFmIrgZTXQlSJmrqr1fhPAaspsIyGoREyIfhEz5EwHsmDNOV8/ZR2IkIlWyP/6AT7kZYfzwmba40z0ZgNvSAzcTifnIhwjn7Uoi3R1pNUpiUqC1pHFAhJYw4tRZRGr6XEpmKO6l3z+YBYsL5pPd3Z8W2i19kt8=
        System.out.println(Base64.getEncoder().encodeToString(sign));
    }

    @Test
    public void verifySignWithPublicKey() throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] publicKeyByte = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyByte);
        PublicKey generatePublic = keyFactory.generatePublic(keySpec);

        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(generatePublic);
        signature.update(signedData.getBytes());
        String sign = "d+YIUvpJQaqKovFmIrgZTXQlSJmrqr1fhPAaspsIyGoREyIfhEz5EwHsmDNOV8/ZR2IkIlWyP/6AT7kZYfzwmba40z0ZgNvSAzcTifnIhwjn7Uoi3R1pNUpiUqC1pHFAhJYw4tRZRGr6XEpmKO6l3z+YBYsL5pPd3Z8W2i19kt8=";
        boolean verify = signature.verify(Base64.getDecoder().decode(sign));
        System.out.println(verify);
    }

}
